home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Software Vault: The Diamond Collection
/
The Diamond Collection (Software Vault)(Digital Impact).ISO
/
cdr40
/
radserv.zip
/
TTY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1995-01-23
|
13KB
|
458 lines
/*
* %W% %E% %U%
*
* Routines for communication through an NT supported serial port (done
* "the right way"). These routines can be used to develop code for
* talking to a radio (or rotator with rs232 interface, etc.)
*/
#include "radextrn.h"
#include "vsttype.h"
BOOL
TTYOpen(tty_t *tp )
{
char portname[24];
BOOL result;
COMMTIMEOUTS CommTimeOuts ;
extern BOOL TTYSetup(tty_t *);
sprintf(portname, "\\\\.\\COM%d", tp->tt_portno);
tp->tt_ttyh = CreateFile( portname, GENERIC_READ | GENERIC_WRITE,
0 /* Exclusive Access */, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_OVERLAPPED, NULL);
if (tp->tt_ttyh == INVALID_HANDLE_VALUE) {
sprintf(tmpbuf,"Cannot open COM%d - error %d\n", tp->tt_portno, GetLastError());
usermsg(tmpbuf);
return FALSE;
}
CommTimeOuts.ReadIntervalTimeout = 0xffffffff ; /* Indefinite */
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 0xffffffff; /* indefinite */
SetCommTimeouts(tp->tt_ttyh, &CommTimeOuts);
result = TTYSetup(tp);
if (!result) {
CloseHandle(tp->tt_ttyh) ;
usermsg("Cannot set up TTY");
return FALSE;
}
SetCommMask(tp->tt_ttyh, EV_RING | EV_RXCHAR | EV_DSR | EV_RLSD | EV_BREAK);
SetupComm(tp->tt_ttyh, 4096, 4096);
if ((tp->tt_RdEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) == INVALID_HANDLE_VALUE) {
CloseHandle(tp->tt_ttyh);
usermsg("Cannot Create TTY RdEvent");
return FALSE;
}
memset (&tp->tt_RdOverlap, 0, sizeof(OVERLAPPED));
tp->tt_RdOverlap.hEvent = tp->tt_RdEvent;
if ((tp->tt_WrEvent = CreateEvent(NULL,TRUE,FALSE,NULL)) == INVALID_HANDLE_VALUE) {
CloseHandle(tp->tt_ttyh);
usermsg("Cannot Create TTY WrEvent");
return FALSE;
}
memset (&tp->tt_WrOverlap, 0, sizeof(OVERLAPPED));
tp->tt_WrOverlap.hEvent = tp->tt_WrEvent;
/*
* If no hardware handshaking desired, raise DTR and RTS
*/
if (!(tp->tt_flags & TTY_DSRDTR))
EscapeCommFunction( tp->tt_ttyh, SETDTR);
Sleep(200);
if (!(tp->tt_flags & TTY_RTSCTS))
EscapeCommFunction( tp->tt_ttyh, SETRTS);
return TRUE;
}
static BOOL
TTYSetup ( tty_t *tp )
{
DCB dcb ;
dcb.DCBlength = sizeof(DCB);
GetCommState(tp->tt_ttyh, &dcb) ;
dcb.BaudRate = tp->tt_baudrate ;
dcb.ByteSize = tp->tt_databits ;
dcb.Parity = tp->tt_parity ;
dcb.StopBits = tp->tt_stopbits ;
if (dcb.fOutxDsrFlow = ((tp->tt_flags & TTY_DSRDTR) != 0))
dcb.fDtrControl = DTR_CONTROL_HANDSHAKE ;
else
dcb.fDtrControl = DTR_CONTROL_ENABLE ;
dcb.fDsrSensitivity = 0;
if (dcb.fOutxCtsFlow = ((tp->tt_flags & TTY_RTSCTS) != 0))
dcb.fRtsControl = RTS_CONTROL_HANDSHAKE ;
else
dcb.fRtsControl = RTS_CONTROL_ENABLE ;
dcb.fInX = dcb.fOutX = (BYTE) ((tp->tt_flags & TTY_XONXOFF) != 0);
dcb.fTXContinueOnXoff = TRUE;
dcb.fNull = TRUE;
dcb.fAbortOnError = FALSE;
dcb.XonChar = (char )17; /* ASCII XON */
dcb.XoffChar = (char )19; /* ASCII XOFF */
dcb.XonLim = 100;
dcb.XoffLim = 100;
dcb.fBinary = TRUE ;
dcb.fParity = (tp->tt_parity != NOPARITY);
return SetCommState( tp->tt_ttyh, &dcb ) ;
}
static BOOL
TTYClose(tty_t *tp)
{
BOOL status;
/* Stop receiving event notifications */
if (!tp->tt_ttyh)
return TRUE;
SetCommMask( tp->tt_ttyh, 0);
/* Drop RTS */
EscapeCommFunction( tp->tt_ttyh, CLRRTS);
Sleep(100);
/* Drop DTR */
EscapeCommFunction( tp->tt_ttyh, CLRDTR);
Sleep(100);
/* Purge all data in all buffers */
PurgeComm( tp->tt_ttyh, PURGE_TXABORT | PURGE_RXABORT |
PURGE_TXCLEAR | PURGE_RXCLEAR );
/* Release resources */
if (status = CloseHandle(tp->tt_ttyh)) {
tp->tt_ttyh = NULL;
CloseHandle(tp->tt_RdEvent);
DeleteObject(tp->tt_RdEvent);
CloseHandle(tp->tt_WrEvent);
DeleteObject(tp->tt_WrEvent);
}
return status;
}
/*
* Read up to maxlen chars into buf. return 0 if nothing available,
* less than zero if an error, or the number of chars received and read.
*/
static int
TTYRead(tty_t *tp, char * buf, int maxlen, int *error )
{
BOOL status;
COMSTAT ComStatus;
DWORD errors, len;
int lerror;
*error = 0;
ClearCommError(tp->tt_ttyh, &errors, &ComStatus ) ;
if (errors > 0) {
*error = (int) errors;
return -1;
}
len = min((int)maxlen, (int)ComStatus.cbInQue);
if (len > 0) {
status = ReadFile( tp->tt_ttyh, buf, len, &len, &tp->tt_RdOverlap) ;
if (!status) {
if ((lerror = GetLastError()) == ERROR_IO_PENDING) {
if (WaitForSingleObject( tp->tt_RdOverlap.hEvent, 20000)) {
*error = GetLastError();
return -1;
}
else {
GetOverlappedResult( tp->tt_ttyh, &tp->tt_RdOverlap, &len, FALSE ) ;
tp->tt_RdOverlap.Offset += len;
}
}
else {
printf("\n<Line error %08x>\n", lerror);
*error = lerror;
return -1;
}
}
}
return len;
}
/*
* Write a character to tty port. (Should really return status...)
*/
static void
TTYWriteChar(tty_t *tp, char byte)
{
int status, error;
DWORD written;
status = WriteFile( tp->tt_ttyh, (LPSTR) &byte, 1,
&written, &tp->tt_WrOverlap);
if (!status) {
if ((error = GetLastError()) == ERROR_IO_PENDING) {
status = WaitForSingleObject( tp->tt_WrOverlap.hEvent, 10000);
if ( status == WAIT_OBJECT_0 ) {
GetOverlappedResult( tp->tt_ttyh, &tp->tt_WrOverlap, &written, FALSE );
tp->tt_WrOverlap.Offset += written;
}
else {
/* Other Error occured (including deadlock or even an actual
* timeout caused by other load). */ ;
}
}
else {
/* Other I/O error occured. System could not initiate the write */ ;
}
}
}
/*
* Write an array of characters to tty port
*/
static void
TTYWrite(tty_t *tp, char *bufp, int buflen)
{
for (; buflen > 0; buflen--)
TTYWriteChar(tp, *bufp++);
}
/*
*****************************************************************************
* *** ALL CODE BELOW IS JUST A SAMPLE *** *
* *
* SAMPLE ROUTINE -- THIS ONE IS SIMPLY A (VERY) DUMB TERMINAL EMULATOR. *
* IT IS HERE TO SHOW THAT WE CAN ACTUALLY DO COMx READS and WRITES *
*****************************************************************************
*/
static HANDLE hConOutput, hConInput, rthread, wthread;
static DWORD oldmode;
HANDLE getwt(void) /* see comments below about compiler optimization problems */
{
return wthread;
}
HANDLE getrt(void)
{
return rthread;
}
BOOL
TTYProc(tp)
tty_t *tp;
{
DWORD dummy, mode;
extern void Reader(tty_t *);
extern void Writer(tty_t *);
if (wthread || rthread) {
return TRUE;
}
if (!TTYOpen(tp))
return FALSE;
Sleep(100);
/*
* Set Keyboard input to uncooked mode (no line delimiter, no echo)
*/
hConInput = GetStdHandle(STD_INPUT_HANDLE);
hConOutput = GetStdHandle(STD_OUTPUT_HANDLE);
if (!hConInput || !hConOutput)
return FALSE;
if (GetConsoleMode(hConInput, &oldmode) == FALSE) {
CloseHandle(hConInput);
CloseHandle(hConOutput);
return FALSE;
}
mode = oldmode; /* Keep a copy for later restoration */
mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
if (SetConsoleMode(hConInput, mode) == FALSE) {
CloseHandle(hConInput);
CloseHandle(hConOutput);
return FALSE;
}
/*
* Create auxiliary thread to read the COM port and write to screen
*/
wthread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL, (DWORD)0,
(LPTHREAD_START_ROUTINE)Writer, (LPVOID)tp,
(DWORD)0, (LPDWORD)&dummy);
if (wthread == INVALID_HANDLE_VALUE) {
CloseHandle(hConInput);
CloseHandle(hConOutput);
return FALSE;
}
rthread = CreateThread ((LPSECURITY_ATTRIBUTES)NULL, (DWORD)0,
(LPTHREAD_START_ROUTINE)Reader, (LPVOID)tp,
(DWORD)0, (LPDWORD)&dummy);
if (rthread == INVALID_HANDLE_VALUE) {
CloseHandle(hConInput);
CloseHandle(hConOutput);
return FALSE;
}
return TRUE;
}
static void
Writer(tp)
tty_t *tp;
{
int rd;
char c;
diag("Begin Writer Thread\n");
Sleep(100);
/*
* Begin main thread. Read keyboard and write to the COM port.
*/
for(;;) {
if (ReadFile(hConInput, &c, 1, &rd, NULL) == FALSE)
break;
if (rd > 0)
TTYWriteChar(tp, c);
if (!getrt()) {
break;
}
}
if (getrt()) {
(void) TerminateThread(rthread, 0);
rthread = NULL;
}
TTYClose(tp);
(void) SetConsoleMode(hConInput, oldmode); /* if we can't set , tuff */
CloseHandle(hConInput);
CloseHandle(hConOutput);
wthread = NULL;
Sleep(0);
ExitThread(0);
}
static void
Reader(tty_t *tp)
{
int rd, error, nwr, status;
int EventMask;
char buf[256];
Sleep(400);
diag("Begin Reader thread.\n");
for (;;) {
EventMask = 0;
#ifdef TOTALLYASYNCHRONOUS
/* Wait for 10 seconds for something to happen */
status = WaitCommEvent(tp->tt_ttyh, &EventMask, &tp->tt_RdOverlap);
if (!status) {
error = GetLastError();
if ((unsigned)error == ERROR_IO_PENDING)
WaitForSingleObject(tp->tt_RdEvent, 10000);
else {
break;
}
}
#else
/*
* Wait indefinitely (barring a ^C) for something to
* happen on the COM port.
*/
(void) WaitCommEvent(tp->tt_ttyh, &EventMask, NULL);
#endif
if (EventMask & (EV_DSR| EV_RLSD | EV_BREAK | EV_RING)) {
GetCommModemStatus(tp->tt_ttyh, &status);
if (EventMask & EV_DSR)
diag("\n<DSR %sASSERTED>\n", (status & MS_DSR_ON) ? "" : "DE");
if (EventMask & EV_RLSD);
diag("\n<CARRIER DETECT %sASSERTED>\n", (status & MS_RLSD_ON) ? "" : "DE");
if (EventMask & EV_BREAK)
diag("\n<LINE BREAK>\n");
if ((EventMask & EV_RING) && (status & MS_RING_ON))
diag("\n<RRRRRING!>\n");
}
/* Now attend to the business of reading the port and echoing */
if (EventMask & EV_RXCHAR) {
do {
rd = TTYRead(tp, buf, sizeof buf, &error);
if (rd > 0)
WriteFile(hConOutput, buf, rd, &nwr, NULL);
if (!getwt()) /* see comment below */
break;
} while(rd > 0);
}
}
/*
* If "too high" a level of optimization is used when compiling, this
* thread may not be able to discover that the value of the
* handle "wthread" has changed (i.e., variable kept in register).
* To avoid it, we simply call an external function to return the
* value instead of simply using it here. Hence the call to getwt().
*/
if (getwt()) {
(void) TerminateThread(wthread, 0);
wthread = NULL;
}
TTYClose(tp);
(void) SetConsoleMode(hConInput, oldmode); /* if we can't set , tuff */
CloseHandle(hConOutput);
CloseHandle(hConInput);
rthread = NULL; /* Signal main thread we're exiting */
Sleep(0);
ExitThread(0);
}